<html>
<script>

  function success_() {
    domAutomationController.send(true);
  }

  function failure_() {
    domAutomationController.send(false);
  }

  function isHttps_() {
    return location.protocol === 'https:';
  }

  function setCookie() {
    const samesite_none_secure = '; SameSite=None; Secure';
    document.cookie = 'foo=bar; Max-Age=1000' + (isHttps_() ? samesite_none_secure : '');
    success_();
  }

  function hasCookie() {
    domAutomationController.send(document.cookie.indexOf('foo=bar') != -1);
  }

  function setSessionCookie() {
    const samesite_none_secure = '; SameSite=None; Secure';
    document.cookie = 'bar=session' + (isHttps_() ? samesite_none_secure : '');
    success_();
  }

  function hasSessionCookie() {
    domAutomationController.send(document.cookie == 'bar=session');
  }

  function setCookieStore() {
    cookieStore.set({
      name: 'cookie-name', value: 'cookie-value', sameSite: 'none'
    }).then(success_).catch(failure_);
  }

  function hasCookieStore() {
    cookieStore.get('cookie-name').then(function (cookie) {
      domAutomationController.send(cookie.value == 'cookie-value');
    }).catch(failure_);
  }

  function setLocalStorage() {
    localStorage.setItem('foo', 'bar');
    success_();
  }

  function hasLocalStorage() {
    try {
      domAutomationController.send(localStorage.getItem('foo') == 'bar');
    } catch (e) {
      failure_();
    }
  }

  function setSessionStorage() {
    sessionStorage.setItem('foo', 'bar');
    success_();
  }

  function hasSessionStorage() {
    try {
      domAutomationController.send(sessionStorage.getItem('foo') == 'bar');
    } catch (e) {
      failure_();
    }
  }

  function setServiceWorker() {
    navigator.serviceWorker.register('empty_worker.js').then(function() {
      navigator.serviceWorker.ready.then(success_);
    }).catch(failure_);
  }

  function hasServiceWorker() {
    navigator.serviceWorker.getRegistrations().then(function (registrations) {
      domAutomationController.send(registrations.length > 0);
    }).catch(failure_);
  }

  function setCacheStorage() {
    caches.open("cache").then(function (cache) {
      cache.put("/foo", new Response("bar")).then(success_);
    }).catch(failure_);
  }

  function hasCacheStorage() {
    caches.open("cache").then(function (cache) {
      cache.keys().then(function (keys) {
        domAutomationController.send(keys.length > 0);
      });
    }).catch(failure_);
  }

  function openFile_(name, options, callback, error) {
    window.webkitRequestFileSystem(TEMPORARY, 1024, function (fs) {
      fs.root.getFile(name, options, callback, error);
    }, error);
  }

  function setFileSystem() {
    openFile_('foo.txt', { create: true, exclusive: true }, success_, failure_);
  }

  function hasFileSystem() {
    openFile_('foo.txt', { create: false }, success_, failure_);
  }

  async function setFileSystemAccess() {
    try {
      let dir = await navigator.storage.getDirectory();
      await dir.getFileHandle('foo.txt', {create: true});
      success_();
    } catch (e) {
      failure_();
    }
  }

  async function hasFileSystemAccess() {
    try {
      let dir = await navigator.storage.getDirectory();
      await dir.getFileHandle('foo.txt', { create: false });
      success_();
    } catch (e) {
      failure_();
    }
  }

  async function setStorageFoundation() {
    try {
      let f = await storageFoundation.open('foo');
      // TODO(https://crbug.com/1177307): Implement a more robust deletion
      // strategy that works reliably for open files on Windows 7.
      await f.close();
      success_();
    } catch (e) {
      failure_();
    }
  }

  async function hasStorageFoundation() {
    try {
      let dir = await storageFoundation.getAll();
      domAutomationController.send(dir.indexOf('foo') != -1);
    } catch (e) {
      failure_();
    }
  }

  function setWebSql() {
    try {
      var db = openDatabase('testdb', '1.0', 'a test db', 1024);
      db.transaction(function (tx) {
        tx.executeSql('CREATE TABLE IF NOT EXISTS foo (text)');
        tx.executeSql('INSERT INTO foo (text) VALUES ("bar")');
      }, failure_, success_);
    } catch (e) {
      return failure_();
    }
  }

  function hasWebSql() {
    try {
      var db = openDatabase('testdb', '1.0', 'a test db', 1024);
      var num_results;
      db.transaction(function (tx) {
        tx.executeSql('CREATE TABLE IF NOT EXISTS foo (text)');
        tx.executeSql('SELECT * FROM foo', [], function (tx, results) {
          num_results = results.rows.length;
        });
      }, null, function() { domAutomationController.send(num_results > 0); });
    } catch (e) {
      return failure_();
    }
  }

  function setIndexedDb() {
    var open = indexedDB.open('db', 2);
    open.onupgradeneeded = function() {
      open.result.createObjectStore('store');
    }
    open.onsuccess = function() {
      open.result.close();
      success_();
    }
    open.onerror = failure_;
  }

  function hasIndexedDb() {
    var open = indexedDB.open('db');
    open.onsuccess = function() {
      var hasStore = open.result.objectStoreNames.contains('store');
      open.result.close();
      domAutomationController.send(hasStore);
    }
    open.onerror = failure_;
  }

  function worker_(command) {
    let worker = new Worker("site_data_worker.js");
    worker.onmessage = e => {
      domAutomationController.send(e.data);
    };
    worker.postMessage(command)
  }

  function hasWorkerFileSystemAccess() {
    worker_("hasFileSystemAccess");
  }

  function setWorkerFileSystemAccess() {
    worker_("setFileSystemAccess");
  }

  function hasWorkerCacheStorage() {
    worker_("hasCacheStorage");
  }

  function setWorkerCacheStorage() {
    worker_("setCacheStorage");
  }

  function hasWorkerIndexedDb() {
    worker_("hasIndexedDb");
  }

  function setWorkerIndexedDb() {
    worker_("setIndexedDb");
  }

  function hasWorkerStorageFoundation() {
    worker_("hasStorageFoundation");
  }

  function setWorkerStorageFoundation() {
    worker_("setStorageFoundation");
  }

  function setHistory() {
    history.pushState({}, "foo");
    success_();
  }

  function hasHistory() {
    domAutomationController.send(history.length > 1);
  }

  let sharedWorker; // Global variable to keep worker alive.
  function connectSharedWorker() {
    return new Promise((resolve, reject) => {
      sharedWorker = new SharedWorker("shared_worker.js");
      sharedWorker.onerror = reject;
      sharedWorker.port.onmessage = resolve;
      sharedWorker.port.start();
    });
  }

  function setSharedWorker() {
    connectSharedWorker().then(() => {
      sharedWorker.port.postMessage({ "value": "foo" });
      success_();
    }).catch(failure_);
  }

  async function hasSharedWorker() {
    connectSharedWorker().then(() => {
      sharedWorker.port.onmessage = e => {
        domAutomationController.send(e.data.value === "foo");
      };
      sharedWorker.port.postMessage({});
    }).catch(failure_);
  }

  let lock;
  function setWebLock() {
    navigator.locks.request("foo", l => {
      lock = new Promise((res, rej) => { });
      // Now lock will be held while |lock| exists.
      success_();
      return lock;
    }).catch(failure_);
  }

  function hasWebLock() {
    navigator.locks.query().then(locks => {
      if (locks.held.length)
        domAutomationController.send(locks.held[0].name === "foo");
      else
        failure_();
    }).catch(failure_);
  }
</script>

<body>
  This page is used to test creation and deletion of various site data types.
  The functions are called from BrowsingDataRemoverBrowserTest::HasDataForType
  and BrowsingDataRemoverBrowserTest::SetDataForType.
</body>

</html>
